

#include <string.h>
#include "User.h"
#include "RingChunk.h"
#include "BlockDeviceConfig.h"
#include "BlockDevice.h"

#include "Utility.h"
#include "SoftCrc.h"

#include "Debug.h"


#define CasualUser_MAX		(BD_Sec_QrUserDataNum / 3) * (BD_SectorSize / BD_PageSize) * (BD_PageSize / sizeof(User_T))

RingChunk_T casualUserChunk;

/*----------------------------------------------------------------------*/
static int CasualUser_DummyCheck(RingChunk_T* chunk){
	uint32_t footprint = RingChunk_Footprint(chunk);	
	uint32_t size = chunk->size;
	
	if(footprint > chunk->itemPerPage){
		if(size == 0){
			return 1;
		}
		if((footprint / size) >= 2){
			//冗余50%
			return 1;
		}
	}

	return 0;
}

static void CasualUser_ClearExpire(RingChunk_T * chunk, uint32_t current){
	User_T user;
	
	RingChunk_Seek(chunk, 0, R_SEEK_START);
	while(! RingChunk_CachReadItem(chunk, &user)){
		if(user.stamp2 < current){
			//用户已过期，删除
			RingChunk_RemoveAt(chunk, chunk->cursor - 1u);
		}
	}
}

int CasualUser_Service(uint32_t current){
	int work = 0;
	//每天0点清除过期用户
	if((current % (24 * 60 * 60)) == 0){
		CasualUser_ClearExpire(&casualUserChunk, current);
		work = 1;
	}
	
	if(CasualUser_DummyCheck(&casualUserChunk)){
		Chunk_Clean(&casualUserChunk);
		work = 1;
	}
	if(casualUserChunk.changed){
		RingChunk_UpdateInfo(&casualUserChunk);
	}
	return work;
}


static int CasualUser_DoIncCountMax(RingChunk_T* chunk, uint32_t uid, uint32_t current, uint32_t stamp1, uint32_t stamp2, uint8_t max){
	User_T user;
	uint32_t index;
	uint8_t isNew = 0;
	
	int ret = RingChunk_FindItemNext(chunk, uid, &user, &index);
	if(ret){
		isNew = 1;
	}
	else
	if(user.stamp2 < current){
		isNew = 1;
	}
	
	if(isNew){
		//新用户		
		if(RingChunk_IsFull(chunk)){
			//用户记录已满，拒绝新用户
			return -2;
		}
		user.uid = uid;
		user.stamp1 = stamp1;
		user.stamp2 = stamp2;
		user.count = max;
		user.used = 1;
		memset(user.useFlag, 0xFF, sizeof(user.useFlag));
		return RingChunk_Append(chunk, &user);
	}
	
	if(User_Used(&user) >= max){
		return -1;
	}
	User_IncreaseCount(chunk, index, &user);
	return 0;

}


int CasualUser_IncCountMax(uint32_t uid, uint32_t current, uint32_t stamp1, uint32_t stamp2, uint8_t max){
	int ret;
	BD_Lock();
	ret = CasualUser_DoIncCountMax(&casualUserChunk, uid, current, stamp1, stamp2, max);
	BD_Unlock();
	return ret;
}


void CasualUser_Init(void){
	Chunk_Init(&casualUserChunk, BD_Sec_QrUserStart, BD_Sec_QrUserInfoNum,
		BD_Sec_QrUserData, BD_Sec_QrUserDataNum, sizeof(User_T), CasualUser_MAX);
}



